//
//  寄存器.h
//  面试题
//
//  Created by Toj on 8/11/21.
//

CPU寄存器: 用来暂存指令、地址和数据
AX, BX, CX, DX,
BP, SP, SI, DI.

// 段寄存器
CS, SS ,DS, ES,
IP, PSW.

// MARK: - 通用寄存器
16位 寄存器
AX, BX, CX, DX,
BP, SP, SI, DI.
// 16位 寄存器 逻辑结构
16位也可以分解成8位 即: *H: high, *L: low
16位: 0000 0000 0000 0000
*H位: 0000 0000
*L位:           0000 0000
AX: AH(高八位), AL(低八位)
BX: BH(高八位), BL(低八位)
CX: CH(高八位), CL(低八位)
DX: DH(高八位), DL(低八位)

32位 寄存器, 在【16位】前 +E即是32位
E: expand 扩展
EAX, EBX, ECX, EDX,
EBP, ESP, ESI, EDI.

// 32位 寄存器 逻辑结构
-32位: 0000 0000 0000 0000 0000 0000 0000 0000

L16位:                     0000 0000 0000 0000
L*H位:                     0000 0000
L*L位:                               0000 0000

H16位: 0000 0000 0000 0000
H*H位: 0000 0000
H*L位:           0000 0000

// MARK: - 用途
// 通用寄存器
AX(): 累加器, 数据运算，返回数据结果.
DX(): 数据寄存器, 存放数值, 与AX一起使用.
CX(): 计数寄存器, 记录循环语句的循环次数.
BX(): 基址寄存器, 存储内存地址.
/**
 数据寄存器
 数据寄存器主要用来保存操作数和运算结果等信息, 从而节省读取操作数所需占用总线和访问存储器的时间.
 32位CPU有4个32位的通用寄存器EAX、EBX、ECX和EDX.
 对低16位数据的存取，不会影响高16位的数据.
 这些低16位寄存器分别命名为: AX、BX、CX和DX，它和先前的CPU中的寄存器相一致.
 4个16位寄存器又可分割成8个独立的8位寄存器(AX: AH-AL、BX：BH-BL、CX：CH-CL、DX：DH-DL),
 每个寄存器都有自己的名称, 可独立存取.
 程序员可利用数据寄存器的这种“可分可合”的特性, 灵活地处理字/字节的信息.
 寄存器AX和AL通常称为累加器(Accumulator), 用累加器进行的操作可能需要更少时间.
 累加器可用于乘、除、输入/输出等操作, 它们的使用频率很高; 寄存器BX称为基地址寄存器(Base Register).
 它可作为存储器指针来使用; 寄存器CX称为计数寄存器(Count Register).
 在循环和字符串操作时, 要用它来控制循环次数; 在位操作中, 当移多位时, 要用CL来指明移位的位数; 寄存器DX称为数据寄存器(Data Register).
 在进行乘、除运算时, 它可作为默认的操作数参与运算, 也可用于存放I/O的端口地址.
 在16位CPU中, AX、BX、CX和DX不能作为基址和变址寄存器来存放存储单元的地址,
 但在32位CPU中, 其32位寄存器EAX、EBX、ECX和EDX不仅可传送数据、暂存数据保存算术逻辑运算结果, 而且也可作为指针寄存器, 所以, 这些32位寄存器更具有通用性.
 
 通用寄存器组包括AX、BX、CX、DX4个16位寄存器, 用以存放16位数据或地址. 也可用作8位寄存器. 用作8位寄存器时分别记为AH、AL、BH、BL、CH、CL、DH、DL. 只能存放8位数据, 不能存放地址.
 它们分别是AX、BX、CX、DX的高八位和低八位. 若AX=1234H, 则AH=12H, AL=34H.
 通用寄存器通用性强, 对任何指令, 它们具有相同的功能.
 为了缩短指令代码的长度, 在8086中, 某些通用寄存器用作专门用途.
 例如:
 串指令中必须用CX寄存器作为计数寄存器, 存放串的长度, 这样在串操作指令中不必给定CX的寄存器号, 缩短了串操作指令代码的长度.
 下面一一介绍:
 AX(AH、AL): 累加器.
 有些指令约定以AX(或AL)为源或目的寄存器.
 输入/输出指令必须通过AX或AL实现,
 例如: 端口地址为43H的内容读入CPU的指令为INAL，43H或INAX，43H.
 目的操作数只能是AL/AX，而不能是其他的寄存器
 BX(BH、BL): 基址寄存器.
 BX可用作间接寻址的地址寄存器和基地址寄存器, BH、BL可用作8位通用数据寄存器.
 CX(CH、CL): 计数寄存器.
 CX在循环和串操作中充当计数器, 指令执行后CX内容自动修改, 因此称为计数寄存器.
 DX(DH、DL): 数据寄存器.
 除用作通用寄存器外, 在I/O指令中可用作端口地址寄存器, 乘除指令中用作辅助累加器.
 */

// 指针和变址寄存器
BP(Base Pointer Register): 基址指针寄存器, 存储内存地址.
SP(Stack Pointer Register): 堆栈指针寄存器.

SI(Source Index Register): 源变址寄存器
DI(Destination Index Register): 目的变址寄存器.
/*
2.指针和变址寄存器
BP( Base Pointer Register): 基址指针寄存器.
SP( Stack Pointer Register): 堆栈指针寄存器.
SI( Source Index Register): 源变址寄存器.
DI( Destination Index Register): 目的变址寄存器.
这组寄存器存放的内容是某一段内地址偏移量，用来形成操作数地址，主要在堆栈操作和变址运算中使用。
 BP和SP寄存器称为指针寄存器，与SS联用，为访问现行堆栈段提供方便。
 通常BP寄存器在间接寻址中使用，操作数在堆栈段中，
 由SS段寄存器与BP组合形成操作数地址即BP中存放现行堆栈段中一个数据区的“基址”的偏移量，
 所以称BP寄存器为基址指针
SP寄存器在堆栈操作中使用，PUSH和POP指令是从SP寄存器得到现行堆栈段的段内地址偏移量，
 所以称SP寄存器为堆栈指针，SP始终指向栈顶
寄存器SI和DI称为变址寄存器，通常与DS一起使用，为访问现行数据段提供段内地址偏移量。
在串指令中，其中源操作数的偏移量存放在SⅠ中，
 目的操作数的偏移量存放在DI中，SI和DI的作用不能互换，否则传送地址相反。
 在串指令中，SI、DI均为隐含寻址，此时，SI和DS联用，Dl和ES联用
SP堆栈的栈顶指针
指针寄存器
32位CPU有2个32位通用寄存器EBP和ESP。
 其低16位对应先前CPU中的SBP和SP，对低16位数据的存取，不影响高16位的数据。
 寄存器EBP、ESP、BP和SP称为指针寄存器(Pointer Register)，
 主要用于存放堆栈内存储单元的偏移量，用它们可实现多种存储器操作数的寻址方式
 为以不同的地址形式访问存储单元提供方便。
 指针寄存器不可分割成8位寄存器。
 作为通用寄存器，也可存储算术逻辑运算的操作数和运算结果
*/

/**

 变址寄存器
 32位CPU有2个32位通用寄存器ESI和EDI。
 其低16位对应先前CPU中的SI和DI，对低16位数据的存取，不影响高16位的数据
 寄存器ESI、EDI、SI和DI称为变址寄存器(Index Register)，
 它们主要用于存放存储单元在段内的偏移量，用它们可实现多种存储器操作数的寻址方式(在第3章有详细介绍)，
 为以不同的地址形式访问存储单元提供方便。
 变址寄存器不可分割成8位寄存器。
 作为通用寄存器，也可存储算术逻辑运算的操作数和运算结果
 它们可作一般的存储器指针使用。
 在字符串操作指令的执行过程中，对它们有特定的要求，而且还具有特殊的功能
 */


// 段寄存器. 提供内存单元的段地址
CS(code segment): 代码段寄存器
SS(stack segment): 堆栈段寄存器
DS(data segment): 数据段寄存器
ES(extra segment): 附加段寄存器
GS/ FS: 附加段寄存器

/*
段寄存器
段寄存器是根据内存分段的管理模式而设置的。
 内存单元的物理地址由段寄存器的值和一个偏移量组合而成的，
 这样可用两个较少位数的值组合成一个可访问较大物理空间的内存地址

主要用途编辑 播报
通用寄存器数据
寄存器AX乘、除运算，字的输入输出，中间结果的缓存
AL字节的乘、除运算，字节的输入输出，十进制算术运算
AH字节的乘、除运算，存放中断的功能号
BX存储器指针
CX串操作、循环控制的计数器
CL移位操作的计数器
DX字的乘、除运算，间接的输入输出
变址
寄存器SI存储器指针、串指令中的源操作数指针
DI存储器指针、串指令中的目的操作数指针

3.段寄存器
8086/8088CPU可直接寻址1MB的存储器空间，直接寻址需要20位地址码，
 而所有内部寄存器都是16位的，只能直接寻址6KB，因此采用分段技术来解决。
 将1MB的存储空间分成若干逻辑段，每段最长64KB，这些逻辑段在整个存储空间中可浮动
8086/8088CPU内部设置了4个16位段寄存器，
 它们分别是代码段寄存器CS、数据段寄存器DS、堆栈段寄存器SS、附加段寄存器ES、由它们给出相应逻辑段的首地址，称为“段基址”。
 段基址与段内偏移地址组合形成20位物理地址，段内偏移地址可以存放在寄存器中，也可以存放在存储器中
例如:
 代码段寄存器CS存放当前代码段基地址，IP指令指针寄存器存放了下一条要执行指令的段内偏移地址，其中CS=2000H，IP=001AH。
 通过组合，形成20位存储单元的寻址地址为2001AH。 [5]
代码段内存放可执行的指令代码，数据段和附加段内存放操作的数据，通常操作数在现行数据段中，而在串指令中，
 目的操作数指明必须在现行附加段中。堆栈段开辟为程序执行中所要用的堆栈区，采用先进后出的方式访问它。
 各个段寄存器指明了一个规定的现行段，各段寄存器不可互换使用。
 程序较小时，代码段、数据段、堆栈段可放在一个段内，即包含在64KB之内，
 而当程序或数据量较大时，超过了64KB，那么可以定义多个代码段或数据段、堆栈段、附加段。
 现行段由段寄存器指明段地址，使用中可以修改段寄存器内容，
 指向其他段。有时为了明确起见，可在指令前加上段超越的前缀，以指定操作数所在段。
*/


// 偏移寄存器.
IP/ EIP: 指令指针寄存器
CS + IP 寻址物理地址
/*
 指令指针寄存器
 32位CPU把指令指针扩展到32位，并记作EIP，EIP的低16位与先前CPU中的IP作用相同。
 指令指针EIP、IP(Instruction Pointer)是存放下次将要执行的指令在代码段的偏移量。
 在具有预取指令功能的系统中，下次要执行的指令通常已被预取到指令队列中，除非发生转移情况。
 所以，在理解它们的功能时，不考虑存在指令队列的情况。
 在实方式下，由于每个段的最大范围为64K，所以，EIP中的高16位肯定都为0，
 此时，相当于只用其低16位的IP来反映程序中指令的执行次序
 
 
 4.指令指针寄存器IP
 8086/8088CPU中设置了一个16位指令指针寄存器IP，
 用来存放将要执行的下一条指令在现行代码段中的偏移地址。
 程序运行中，它由BIU自动修改，使IP始终指向下一条将要执行的指令的地址，
 因此它是用来控制指令序列的执行流程的，是一个重要的寄存器。
 8086程序不能直接访问IP，但可以通过某些指令修改IP的内容。
 例如，当遇到中断指令或调用子程序指令时，8086自动调整IP的内容，
 将IP中下一条将要执行的指令地址偏移量入栈保护，待中断程序执行完毕或子程序返回时，
 可将保护的内容从堆栈中弹出到IP，使主程序继续运行。
 在跳转指令时，则将新的跳转目标地址送入IP，改变它的内容，实现了程序的转移
 */


// 标志寄存器.
Flag/ EFlag: 标志寄存器
8个标志位:
CF(Carry Flag): 进位标志, 进位1, 否则0
PF(Parity Flag): 奇偶标志, 1的个数为偶数1, 否则0
AF(Auxiliary Carry Flag): 辅助进位标志, 有进位1, 默认0
OF(Overflow Flag): 溢出标志1代表溢出, 默认0
SF(Sign Flag): 符号标志, 负为1, 默认0
ZF(Zero Flag): 零标志, 运算结果为0 -> ZF就为1, 默认为0
DF(): 方向标志, 在串处理中控制防线
IF(): 中断标志

/**
 5.标志寄存器FR
 标志寄存器FR也称程序状态字寄存器。 [5]
 FR是16位寄存器，其中有9位有效位用来存放状态标志和控制标志。
 状态标志共6位，CF、PF、AF、ZF、SF和OF，用于寄存程序运行的状态信息，
 这些标志往往用作后续指令判断的依据。控制标志有3位，IF、DF和TF，用于控制CPU的操作，是人为设置的
 存放代码满足条件编辑 播报
 (1)代码要存得进；
 (2)代码要记得住；
 (3)代码要取得出
 寄存器是由具有存储功能的触发器组合起来构成的。
 一个触发器可以存储1位2进制代码，存放n位2进制代码的寄存器，需用n个触发器来构成
 寄存器中的触发器只要求它具有置1、置0的功能即可，因而无论用何种类型的触发器都可组成寄存器
 按照功能的不同，寄存器可分为基本寄存器和移位寄存器两大类。
 基本寄存器只能并行送入数据，需要时也只能并行输出。
 移位寄存器中的数据可以在移位脉冲作用下依次逐位右移或左移，数据既可以并行输入、并行输出，
 也可以串行输入、串行输出，还可以并行输入、串行输出或串行输入、并行输出，十分灵活，用途也很广
 寄存器组织编辑 播报
 ARM微处理器共有37个32位寄存器，其中31个为通用寄存器，6个为状态寄存器
 但是这些寄存器不能被同时访问，具体哪些寄存器是可编程访问的，取决于微处理器的工作状态及具体的运行模式
 但在任何时候，通用寄存器R14~R0、程序计数器PC、一个或两个状态寄存器都是可访问的
 ARM9处理器共有37个32位长的寄存器，这些寄存器包括：
 (1) RO～R12：均为32位通用寄存器，用于数据操作。
 但是注意：绝大多数16位Thumb指令只能访问R0～R7，而32位Thumb -2指令可以访问所有寄存器
 (2)堆栈指针：堆栈指针的最低两位永远是O，这意味着堆栈总是4字节对齐的
 (3)链接寄存器：当呼叫一个子程序时，由R14存储返回地址
 (4)程序计数器：指向当前的程序地址，如果修改它的值，就能改变程序的执行流
 (5)6个状态寄存器（1个CPSR、5个SPSR），用以标识CPU的工作状态及程序的运行状态，
 均为32位，目前只使用了其中的一部分
 Cortex-A8处理器有40个32位长的寄存器，多了监控模式下的寄存器，
 如RO～R12、R15、CPSR通用，R13_ mon、R14_mon、SPSR_mon三个专用寄存器
 寄存器寻址编辑 播报
 寄存器寻址就是利用寄存器中的数值作为操作数，
 这种寻址方式是各类微处理器经常采用的一种方式，也是一种执行效率较高的寻址方式
 寄存器寻址是指操作数存放在CPU内部的寄存器中，指令中给出操作数所在的寄存器名。
 寄存器操作数可以是8位寄存器AH、AL、BH、BL、CH、CL、DH、DL，
 也可以是16位寄存器AX、BX、CX、DX、SP、BP、SI、DI等。
 因为寄存器寻址不需要通过总线操作访问存储器，所以指令执行速度比较快
 寄存器寻址( Register Addressing)
 是以通用寄存器的内容作为操作数的寻址方式，在该寻址方式下，操作数存放在寄存器中。
 寄存器寻址方式的寻址对象为：A，B，DPTR，R0~R7。
 其中，B仅在乘除法指令中为寄存器寻址，在其他指令中为直接寻址。
 A可以按寄存器寻址又可以直接寻址，直接寻址时写成ACC
 */

// MARK: - 分类
// MARK: 数据寄存器
主要用来保存操作数和运算结果等信息,
从而节省读取操作数所需占用总线和访问存储器的时间.

32位CPU有4个32位的通用寄存器EAX、EBX、ECX、EDX.
对低16位数据的存取, 不会影响高16位的数据.
这些低16位寄存器分别命名为: AX、BX、CX和DX, 它和先前的CPU中的寄存器相一致.

4个16位寄存器又可分割成8个独立的8位寄存器
AX：AH-AL
BX：BH-BL
CX：CH-CL
DX：DH-DL
每个寄存器都有自己的名称，可独立存取
程序员可利用数据寄存器的这种“可分可合”的特性，灵活地处理字/字节的信息。
寄存器AX和AL通常称为累加器(Accumulator)，用累加器进行的操作可能需要更少时间。
累加器可用于乘、除、输入/输出等操作，它们的使用频率很高； 寄存器BX称为基地址寄存器(Base Register)。
它可作为存储器指针来使用； 寄存器CX称为计数寄存器(Count Register)。
在循环和字符串操作时，要用它来控制循环次数；在位操作中，当移多位时，要用CL来指明移位的位数； 寄存器DX称为数据寄存器(Data Register)。
在进行乘、除运算时，它可作为默认的操作数参与运算，也可用于存放I/O的端口地址。
在16位CPU中，AX、BX、CX和DX不能作为基址和变址寄存器来存放存储单元的地址，但在32位CPU中，其32位寄存器EAX、EBX、ECX和EDX不仅可传送数据、暂存数据保存算术逻辑运算结果，而且也可作为指针寄存器，所以，这些32位寄存器更具有通用性。详细内容请见第3.8节——32位地址的寻址方式。


// MARK: EFLAGS: 标志寄存器

// MARK: 偏移寄存器:
BP: 基址寄存器
SP: 堆栈指针寄存器

CS: 指令起始段地址位
IP/ EIP: 指令指针寄存器
// CS + IP 确定从内存哪里开始执行指令, 执行指令过程看【指令.h】
BX: 基址寄存器, 存储内存地址

SI(源变址寄存器): 源变址寄存器,通常存放处理数据的内存地址
DI: 亩地变址寄存器, 存放处理后的数据内存地址
二者互相配合使用
 
地址加法器: 基础地址 + 偏移地址 = 物理地址
地址加法器: 段地址 * 16(10H = 16进制10) + 偏移地址 = 物理地址

/*
 那么各种寄存器的作用分别是什么呢？这里简要介绍一下。
 （一）数据寄存器（EAX EBX ECX EDX）：
 1.EAX——累加寄存器（Accumulator Register）
 低16位（AX=AH&AL）
 作用：实现乘除运算、中间结果缓存
 2.EBX——基址寄存器（Base Register）
 低16位（BX=BH&BL）
 作用：存储器指针
 3.ECX——计数寄存器（Count Register）
 低16位（CX=CH&CL）
 作用：实现循环控制、进行串操作
 4.EDX——数据寄存器（Data Register）
 低16位（DX=DH&DL）
 作用：实现乘除运算、中间结果缓存（与EAX类似）
 （二）变址寄存器和指针寄存器（ESI EDI EBP ESP）
 1.ESI——源变址寄存器（Source Index Register）
 低16位（SI）
 作用：作为存储器指针、在串指令中作为源操作数指针
 2.EDI——目的变址寄存器（Destination Index Register）
 低16位（DI）
 作用：作为存储器指针、在串指令中作为目的操作数指针
 3.EBP——基址指针寄存器（Base Pointer Register）
 低16位（BP）
 作用：指向栈帧底部或栈底（栈帧底部和栈底是两个不同的概念）
 4.ESP——堆栈指针寄存器（Stack Pointer Register）
 低16位（SP）
 作用：指向栈帧顶部或栈顶（栈帧顶部和栈顶是两个不同的概念）
 （三）段寄存器（CS DS SS ES FS GS）
 段寄存器作用——存储段地址
 1.CS——代码段寄存器（Code Segment Register）
 作用：存储代码段的段地址
 2.DS——数据段寄存器（Data Segment Register）
 作用：存储数据段的段地址
 3.SS——堆栈段寄存器（Stack Segment Register）
 作用：存储堆栈段的段地址
 4.ES——附加段寄存器（Extra Segment Register）
 作用：存储附加段的段地址
 5.新增附加段寄存器：
 FS——附加段寄存器（Extra Segment Register）
 GS——附加段寄存器（Extra Segment Register）
 （四）EIP——指令指针寄存器（Instruction Pointer Register）
 1.内存中的地址表示
 物理地址=段地址+偏移地址
 段地址存储在段寄存器中、偏移地址是相对于段地址的偏移量。
 EIP寄存器存放下一个机器指令的地址，指向下一条代码指令，并随程序的执行不断变化。
 （五）EFLAGS——标志寄存器
 1.CF——进位标志（Carry Flag）
 2.PF——奇偶标志（Parity Flag）
 3.AF——辅助进位标志（Auxiliary Carry Flag）
 4.OF——溢出标志（Overflow Flag）
 5.SF——符号标志（Sign Flag）
 6.ZF——零标志（Zero Flag）
 */
